package com.smmisia.article.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smmisia.article.api.AuthService;
import com.smmisia.article.bo.CreateGroupBO;
import com.smmisia.article.entity.Group;
import com.smmisia.article.entity.GroupMember;
import com.smmisia.article.entity.User;
import com.smmisia.article.entity.convetor.GroupConvertor;
import com.smmisia.article.exception.SocketException;
import com.smmisia.article.mapper.GroupMapper;
import com.smmisia.article.mapper.GroupMemberMapper;
import com.smmisia.article.request.CreateGroupRequest;
import com.smmisia.article.response.socket.FriendResponse;
import com.smmisia.article.response.socket.GroupResponse;
import com.smmisia.article.service.GroupService;
import com.smmisia.common.Result.Result;
import com.smmisia.common.entity.auth.UserDTO;
import com.smmisia.common.entity.auth.convertor.UserConvertor;
import com.smmisia.common.request.feign.request.FeignCreateGroupRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;
import java.util.stream.Collectors;


@Service
public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group>
        implements GroupService {

    @Autowired
    private GroupMapper groupMapper;

    @Autowired
    private GroupMemberMapper groupMemberMapper;

    @Autowired
    private AuthService authService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> create(FeignCreateGroupRequest request) {
        CreateGroupBO bo = CreateGroupBO.builder()
                .accompanyId(request.getAccompanyId())
                .userId(request.getUserId())
                .groupName(request.getGroupName())
                .description(request.getDescription())
                .build();
        Group group = Group.create(bo);
        Assert.isTrue(groupMapper.insert(group) > 0,
                () -> new SocketException("创建群组失败"));
        insertLeader(group.getId());
        return Result.ok(true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> add(Integer accompanyId, Integer userId) {
        Group group = Optional.ofNullable(groupMapper.selectOne(Wrappers
                        .lambdaQuery(Group.class)
                        .eq(Group::getAccompanyId, accompanyId)))
                .orElseThrow(() -> new SocketException("群组不存在"));
        insertMember(group.getId(), userId);
        return Result.ok(true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> disband(Integer accompanyId) {
        Group group = Optional.ofNullable(groupMapper.selectOne(Wrappers
                        .lambdaQuery(Group.class)
                        .eq(Group::getAccompanyId, accompanyId)))
                .orElseThrow(() -> new SocketException("群组不存在"));
        Assert.isTrue(groupMapper.deleteById(group.getId()) > 0,
                () -> new SocketException("删除群组失败"));
        Assert.isTrue(groupMemberMapper.delete(
                        Wrappers.lambdaQuery(GroupMember.class)
                                .eq(GroupMember::getGroupId, group.getId())) > 0,
                () -> new SocketException("删除群组用户失败"));
        return Result.ok(true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> addGroup(Integer groupId) {
        Optional.ofNullable(groupMapper.selectById(groupId))
                .orElseThrow(() -> new SocketException("群组不存在"));
        GroupMember member = GroupMember.builder()
                .groupId(groupId)
                .userId(StpUtil.getLoginIdAsInt())
                .role("member")
                .build();
        Assert.isTrue(groupMemberMapper.insert(member) > 0,
                () -> new SocketException("加入群组失败"));
        return Result.ok(true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> createGroup(CreateGroupRequest request) {
        CreateGroupBO bo = CreateGroupBO.builder()
                .accompanyId(null)
                .userId(StpUtil.getLoginIdAsInt())
                .groupName(request.getGroupName())
                .description(request.getDescription())
                .build();
        Group group = Group.create(bo);
        Assert.isTrue(groupMapper.insert(group) > 0,
                () -> new SocketException("创建群组失败"));
        insertLeader(group.getId());
        return Result.ok(true);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> removeGroup(Integer id) {
        Optional.ofNullable(groupMapper.selectById(id))
                .orElseThrow(() -> new SocketException("群组不存在"));
        Assert.isTrue(groupMapper.deleteById(id) > 0,
                () -> new SocketException("删除群组失败"));
        Assert.isTrue(groupMemberMapper.delete(
                        Wrappers.lambdaQuery(GroupMember.class)
                                .eq(GroupMember::getGroupId, id)) > 0,
                () -> new SocketException("删除群组用户失败"));
        return Result.ok(true);
    }

    @Override
    public Result<FriendResponse> listGroupMember(Integer groupId) {
        Optional.ofNullable(groupMapper.selectById(groupId))
                .orElseThrow(() -> new SocketException("群组不存在"));

        return Result.ok(FriendResponse.builder()
                .user(groupMemberMapper.selectList(
                                Wrappers.lambdaQuery(GroupMember.class)
                                        .eq(GroupMember::getGroupId, groupId)
                                        .select(GroupMember::getUserId)
                        )
                        .stream()
                        .map(GroupMember::getUserId)
                        .collect(Collectors.toList())
                        .stream()
                        .map(authService::info)
                        .map((user)->{
                            com.smmisia.article.dto.user.UserDTO users = com.smmisia.article.dto.user.UserDTO.builder()
                                    .id(user.getId())
                                    .username(user.getUsername())
                                    .uid(user.getUid())
                                    .email(user.getEmail())
                                    .avatar(user.getAvatar())
                                    .build();
                            return users;
                        })
                        .collect(Collectors.toList()))
                .build());
    }


    @Override
    public Result<GroupResponse> listGroup() {
        return Result.ok(
                GroupResponse.builder()
                        .groups(groupMapper.selectList(
                                        Wrappers.lambdaQuery(Group.class)
                                                .eq(Group::getUserId, StpUtil.getLoginIdAsInt()))
                                .stream()
                                .map(GroupConvertor.INSTANCE::toGroupDTO)
                                .collect(Collectors.toList())));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> quitGroup(Integer groupId) {
        Optional.ofNullable(groupMapper.selectById(groupId))
                .orElseThrow(() -> new SocketException("群组不存在"));
        quitGroup(groupId, StpUtil.getLoginIdAsInt());
        return Result.ok(true);
    }

    // 插入群主
    public void insertLeader(Integer groupId) {
        GroupMember member = GroupMember.builder()
                .groupId(groupId)
                .userId(StpUtil.getLoginIdAsInt())
                .role("leader")
                .build();
        Assert.isTrue(groupMemberMapper.insert(member) > 0,
                () -> new SocketException("插入用户失败"));
    }

    //插入普通用户
    public void insertMember(Integer groupId, Integer userId) {
        GroupMember member = GroupMember.builder()
                .groupId(groupId)
                .userId(userId)
                .role("member")
                .build();
        Assert.isTrue(groupMemberMapper.insert(member) > 0,
                () -> new SocketException("插入用户失败"));
    }

    //退群
    public void quitGroup(Integer groupId, Integer userId) {
        GroupMember groupMember = groupMemberMapper.selectById(groupId);
        if (groupMember.getRole().equals("leader")) {
            throw new SocketException("群主不能退出群组");
        }
        Assert.isTrue(groupMemberMapper.delete(
                        Wrappers.lambdaQuery(GroupMember.class)
                                .eq(GroupMember::getGroupId, groupId)
                                .eq(GroupMember::getUserId, userId)) > 0,
                () -> new SocketException("退出群组失败"));
    }

}




